package org.newlucene.core.index;

import java.io.IOException;

import org.newlucene.core.store.Directory;
import org.newlucene.core.store.InputStream;

/** This stores a monotonically increasing set of <Term, TermInfo> pairs in a
 * Directory.  Pairs are accessed either by Term or by ordinal position the
 * set.  */
final class SegmentTermInfos
{
	private InputStream input;
	private FieldInfos fieldInfos;
	private int size;
	private int position = -1;

	private Term term = new Term("", "");
	private int docCount = 0;
	private long freqPointer = 0;

	private char[] buffer = {};
	
	private SegmentTermInfosIndex tii;
	
	public SegmentTermInfos(Directory dir, String segment, FieldInfos fis) throws IOException 
	{
		input = dir.openFile(segment + ".tis");
		fieldInfos = fis; 
		size = input.readInt();
		tii = new SegmentTermInfosIndex(dir, segment, fieldInfos);
	}
 
	/** starting at or after the named term. */
	public final TermInfo seek(Term term) throws IOException 
	{
		if (size == 0)
		{
			return null;
		}
		int tiiOffset = tii.seekIndexOffset(term);
		seekTermInfos(tiiOffset);
		return scanTermInfos(term);
	}
	
	private final void seekTermInfos(int tiiOffset) throws IOException
	{	
		input.seek(tii.indexPointers[tiiOffset]);
		position = (tiiOffset * TermInfosWriter.INDEX_INTERVAL) - 1;
		term = tii.indexTerms[tiiOffset];
		TermInfo ti = tii.indexInfos[tiiOffset];
		docCount = ti.docCount;
		freqPointer = ti.freqPointer;
		growBuffer(term.text.length());		  // copy term text into buffer
	}

	/** Scans within block for matching term. */
	private final TermInfo scanTermInfos(Term term) throws IOException 
	{
		while (term.compareTo(term()) > 0 && next()) 
		{}
		if (term() != null && term.compareTo(term()) == 0)
		{
			return new TermInfo(docCount, freqPointer);
		}
		else
		{
			this.term = null;
			docCount = 0;
			freqPointer = 0;
			return null;
		}
	}
	
	/** Increments the enumeration to the next element.  True if one exists.*/
	public final boolean next() throws IOException 
	{
		if (position++ >= size - 1) 
		{
			term = null;
			docCount = 0;
			freqPointer = 0;
			return false;
		}

		term = readTerm();
		docCount = input.readVInt();	  // read doc freq
		freqPointer += input.readVLong();	  // read freq pointer    

		return true;
	}

	private final Term readTerm() throws IOException 
	{
		int start = input.readVInt();
		int length = input.readVInt();
		int totalLength = start + length;
		if (buffer.length < totalLength)
		{
			growBuffer(totalLength);
		}
		
		input.readChars(buffer, start, length);
		return new Term(fieldInfos.getFieldInfo(input.readVInt()).name, new String(buffer, 0, totalLength));
	}

	private final void growBuffer(int length) 
	{
		buffer = new char[length];
		for (int i = 0; i < term.text.length(); i++)  // copy contents
		{
			buffer[i] = term.text.charAt(i);
		}
	}

	/** Returns the current Term in the enumeration.
    	Initially invalid, valid after next() called for the first time.*/
	public final Term term() 
	{
		return term;
	}

	public final TermInfo termInfo()
	{
		return new TermInfo(docCount, freqPointer);
	}
	
	/** Closes the enumeration to further activity, freeing resources. */
	public final void close() throws IOException 
	{
		input.close();
	}
}